﻿using AdvancedCollections.TreeHelper;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AdvancedCollections
{
    public class BinaryTree<T> : ISet<T>
    {
        protected IComparer<T> _comparer;
        protected BinaryTreeNode<T> _root;

        public BinaryTree()
            : this(DefaultComparer)
        {
        }

        public BinaryTree(IComparer<T> comparer)
        {
            _comparer = comparer;
            _root = CreateRoot(); ;
        }

        public static IComparer<T> DefaultComparer
        {
            get { return Comparer<T>.Default; }
        }

        public virtual int Count
        {
            get;
            protected set;
        }

        public virtual bool IsReadOnly
        {
            get { return false; }
        }

        public virtual bool Add(T item)
        {
            if (item == null)
                throw new ArgumentNullException("item");

            return InternalAdd(item);
        }

        public virtual void Clear()
        {
            _root = CreateRoot();
        }

        public virtual bool Contains(T item)
        {
            if (item == null)
                throw new ArgumentNullException("item");

            return _root.Contains(item);
        }

        public virtual void CopyTo(T[] array, int arrayIndex)
        {
            if (array == null)
                throw new ArgumentNullException("array");

            if ((array.Length - arrayIndex) < Count)
                throw new ArgumentException("The number of elements in the BinaryTree is greater than the available space from arrayIndex to the end of the destination array.");

            InternalCopyTo(array, arrayIndex);
        }

        public virtual void ExceptWith(IEnumerable<T> other)
        {
            throw new NotImplementedException();
        }

        public virtual IEnumerator<T> GetEnumerator()
        {
            return new BinaryTreeEnumerator<T>(_root);
        }

        void ICollection<T>.Add(T item)
        {
            Add(item);
        }

        public virtual void IntersectWith(IEnumerable<T> other)
        {
            throw new NotImplementedException();
        }

        public virtual bool IsProperSubsetOf(IEnumerable<T> other)
        {
            throw new NotImplementedException();
        }

        public virtual bool IsProperSupersetOf(IEnumerable<T> other)
        {
            throw new NotImplementedException();
        }

        public virtual bool IsSubsetOf(IEnumerable<T> other)
        {
            throw new NotImplementedException();
        }

        public virtual bool IsSupersetOf(IEnumerable<T> other)
        {
            throw new NotImplementedException();
        }

        public virtual bool Overlaps(IEnumerable<T> other)
        {
            throw new NotImplementedException();
        }

        public virtual bool Remove(T item)
        {
            if (item == null)
                throw new ArgumentNullException("item");

            return InternalRemove(item);
        }

        public virtual bool SetEquals(IEnumerable<T> other)
        {
            throw new NotImplementedException();
        }

        public virtual void SymmetricExceptWith(IEnumerable<T> other)
        {
            throw new NotImplementedException();
        }

        IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return new BinaryTreeEnumerator<T>(_root);
        }

        public virtual void UnionWith(IEnumerable<T> other)
        {
            throw new NotImplementedException();
        }

        protected virtual BinaryTreeNode<T> CreateRoot()
        {
            return new BinaryTreeNode<T>(null, _comparer);
        }

        protected virtual bool InternalAdd(T item)
        {
            bool added = false;

            added = _root.Add(item);

            if (added)
                Count++;

            return added;
        }

        protected virtual void InternalCopyTo(T[] array, int arrayIndex)
        {
            foreach (var item in this)
            {
                array[arrayIndex++] = item;
            }
        }

        protected virtual bool InternalRemove(T item)
        {
            bool removed = _root.Remove(item, ref _root);

            if (removed)
                Count--;

            return removed;
        }
    }
}